#include "svmTrainConfig.h"
#include <cstring>
#include <cstdio>
#include <cstdlib>

void svmTrainConfig::printHelp() {
	printf("Usage: svmTrain [options] trainingData.svm\n"
		"Options:\n"
		"	-o outputFilename	 Location of output file\n"
		"Kernel types:\n"
		"	-k(default 0)\n"
		"	0 Gaussian or RBF kernel : Phi(x, y; gamma) = exp{-gamma*||x-y||^2}\n"
		"	1 Linear kernel: Phi(x, y) = x . y\n"
		"	2 Polynomial kernel: Phi(x, y; a, r, d) = (ax . y + r)^d\n"
		"	3 Sigmoid kernel: Phi(x, y; a, r) = tanh(ax . y + r)\n"
		"Parameters:\n"
		"	-c	SVM training cost C (default = 10)\n"
		"	-g	Gamma for Gaussian kernel (default = 1/num_features)\n"
		"	-a	Parameter a for Polynomial and Sigmoid kernels (default = 1/num_features)\n"
		"	-r	Parameter r for Polynomial and Sigmoid kernels (default = 1)\n"
		"	-d	Parameter d for Polynomial kernel (default = 3)\n"
		"Convergence parameters:\n"
		"	-t -- tolerance:Termination criterion tolerance (default = 0.001)\n"
		"	-e -- epsilon:Support vector threshold (default = 1e-5)\n"
		"Internal options:\n"
		"	-h	Working selection heuristic:\n"
		"	0: First order\n"
		"	1: Second order\n");
}

void svmTrainConfig::parseCommand(const int &argc, const char** &argv) {
	if(argc < 2) {
		printHelp();
		exit(1);
	}
	int idx;
	for(idx=1;idx<argc;idx++) {
		if(argv[idx][0] != '-') break;
		if(++idx >= argc) break;
		switch(argv[idx-1][1]) {
			case 'v':
				puts("gpusvm version in ix11");
				exit(0);
			case 'f':
				printHelp();
				exit(1);
			case 'c':
				C = (float)atof(argv[idx]);
				break;
			case 'k':
				kType = (KernelType)atoi(argv[idx]);
				break;
			case 'h':
				switch(atoi(argv[idx])) {
					case 0:
						method = FIRSTORDER; break;
					case 1:
						method = SECONDORDER; break;
					default: break;
				}
				break;
			case 't':
				tau = (float)atof(argv[idx]);
				break;
			case 'o':
				outputFilename = (char*)malloc(strlen(argv[idx]));
				strcpy(outputFilename,argv[idx]);
				break;
			case 'a':
				gamma = (float)atof(argv[idx]);
				break;
			case 'r':
				coef = (float)atof(argv[idx]);
				break;
			case 'd':
				degree = (float)atof(argv[idx]);
				break;
			case 'g':
				gamma = (float)atof(argv[idx]);
				break;
			default:
				printHelp();
				exit(1);
		}
	}
	
	trainingFilename = const_cast<char *>(argv[idx]);

	//If outputfilename is null,
	//then add the extention defined above to the inputfilename and set it as outputfile name
	if (outputFilename == NULL) {
		int inputNameLength = strlen(trainingFilename);
		outputFilename = (char*)malloc(sizeof(char)*(inputNameLength + extLength));
		strcpy(outputFilename,trainingFilename);
		char* period = strrchr(outputFilename, '.');
		if (period == NULL)  //try to overwrite the file extention name of inputfile
			period = outputFilename + inputNameLength;
		strncpy(period, extModel, extLength);
	}
}

void svmTrainConfig::checkParam(int nDimension) {
	if (kType == LINEAR) {
		printf("> Linear kernel\n");
	} else if (kType == POLYNOMIAL) {
		if (degree == 0.0f) degree = 3.0f;
		if (gamma == 0.0f) gamma = 1.0f/nDimension;
		if (coef == 0.0f) coef = 1.0f;
		printf("> Polynomial kernel: a = %f, r = %f, d = %f\n", gamma, coef, degree);
		if (gamma < 0.0f || coef < 0.0f || degree < 1.0f) {
			printf("!!!!!Invalid parameters\n");
			exit(1);
		}
	} else if (kType == GAUSSIAN) {
		if (gamma == 0.0f) gamma = 1.0f/nDimension;
		printf("> Gaussian kernel: gamma = %f\n", gamma);
		if (gamma < 0.0f) {
			printf("!!!!!Invalid parameters\n");
			exit(1);
		}
	} else if (kType == SIGMOID) {
		if (gamma == 0.0f) gamma = 1.0f/nDimension;
		if (coef == 0.0f) coef = 1.0f;
		printf("> Sigmoid kernel: a = %f, r = %f\n", gamma, coef);
		if (gamma < 0.0f || coef < 0.0f) {
			printf("!!!!!Invalid Parameters\n");
			exit(1);
		}
	}
}